package com.common.tree;


import java.util.*;

public final class NodeBuilder {

    public static <T extends MenuNode, R extends Tree> List<R> convert(List<T> list) {
        return convert(list, true);
    }


    public static <T extends MenuNode, R extends Tree> List<R> convert(List<T> list, boolean addRoot) {
        return convert(list, new NodeConvert<>(), addRoot);
    }

    public static <T extends MenuNode, R extends Tree, M extends NodeConvert<T, R>> List<R> convert(List<T> list, M m, boolean addRoot) {
        List<R> trees = new LinkedList<>();
        try {
            if (addRoot) {
                trees.add(m.createRootNode());
            }
            Map<String, T> maps = new HashMap<>();
            Map<String, R> map = new HashMap<>();
            for (T t : list) {
                String value = t.getValue();
                map.put(value, m.apply(t));
                maps.put(value, t);
            }
            for (Map.Entry<String, T> entry : maps.entrySet()) {
                T value = entry.getValue();
                String parentValue = value.getParentValue();
                R node = map.get(value.getValue());
                if (m.isRootNode(value)) {
                    trees.add(node);
                } else {
                    R parent = map.get(parentValue);
                    if (parent != null) {
                        parent.add(node);
                    }
                }
            }
        } catch (Exception e) {
            e.printStackTrace();
        }
        return trees;
    }


    public static <T extends Node> List<T> findChildren(List<T> list, T t) {
        NodeFilter<T> filter = new NodeFilter<T>() {
            @Override
            public boolean filter(T t1, T t2) {
                return t1.getValue().equals(t2.getValue());
            }

            @Override
            public boolean isFilter() {
                return true;
            }
        };
        return findChildren(list, t, filter);
    }

    /**
     * 查找树形结构的任意一个节点的所有子节点
     *
     * @param list:包含树形结构的任意数据
     * @param currentNode:     当前节点
     * @param <T>:             满足上下级关系的节点
     * @return
     */
    public static <T extends Node> List<T> findChildren(List<T> list, T currentNode, NodeFilter<T> filter) {
        List<T> linkedList = new LinkedList<>();
        if (currentNode == null || list == null || list.isEmpty()) {
            return linkedList;
        }
        Stack<EntryWrapper<T>> stack = new Stack<>();
        Map<String, EntryWrapper<T>> maps = new HashMap<>();
        for (T item : list) {
            EntryWrapper<T> value = EntryWrapper.create(item.getValue(), item.getParentValue(), item);
            maps.put(item.getValue(), value);
        }
        for (Map.Entry<String, EntryWrapper<T>> entry : maps.entrySet()) {
            EntryWrapper<T> value = entry.getValue();
            if (filter.filter(value.getNode(), currentNode)) {
                stack.add(value);
            } else {
                EntryWrapper<T> parent = maps.get(value.getParentValue());
                if (parent != null) {
                    parent.add(value);
                }
            }
        }
        while (!stack.isEmpty()) {
            EntryWrapper<T> node = stack.pop();
            if (!filter.isFilter() || !filter.filter(node.getNode(), currentNode)) {
                linkedList.add(node.getNode());
            }
            List<EntryWrapper<T>> children = node.getChildren();
            if (children != null && !children.isEmpty()) {
                stack.addAll(children);
            }
        }
        return linkedList;
    }

    //移动子节点
    public static <T extends Node> void handlerChildren(List<T> currentNodes, T currentNode, NodeFunction<T> function) {
        Map<String, EntryWrapper<T>> maps = new TreeMap<>((o1, o2) -> {
            Integer x = Integer.valueOf(o1);
            Integer y = Integer.valueOf(o2);
            return x.compareTo(y);
        });
        for (T node : currentNodes) {
            String value = node.getValue();
            maps.put(value, EntryWrapper.create(value, node.getParentValue(), node));
        }

        for (Map.Entry<String, EntryWrapper<T>> entry : maps.entrySet()) {
            EntryWrapper<T> value = entry.getValue();
            String parentValue = value.getParentValue();
            T node = value.getNode();
            if (parentValue.equals(currentNode.getValue())) {
                function.apply(currentNode, node);
            } else {
                EntryWrapper<T> parent = maps.get(parentValue);
                if (parent != null) {
                    function.apply(parent.getNode(), node);
                }
            }
        }
    }

    //判断某个节点是否属于当前节点的子节点
    public static <T extends Node> boolean exists(List<T> currentNodes, T currentNode) {
        for (int i = 0; i < currentNodes.size(); i++) {
            T item = currentNodes.get(i);
            if (item.getValue().equals(currentNode.getValue())) {
                return true;
            }
        }
        return false;
    }
}
